package com.example.xunai.service.ai.impl;

import com.example.xunai.config.AiModelConfig;
import com.example.xunai.dto.request.ai.StreamChatRequest;
import com.example.xunai.dto.request.conversation.CreateConversationRequest;
import com.example.xunai.entity.Conversation;
import com.example.xunai.entity.ConversationMessage;
import com.example.xunai.service.ai.StreamChatService;
import com.example.xunai.service.cache.CacheService;
import com.example.xunai.service.conversation.ConversationMessageService;
import com.example.xunai.service.conversation.ConversationService;
import com.example.xunai.service.user.TokenUsageService;
import com.example.xunai.service.ai.strategy.AiModelFactory;
import com.example.xunai.service.ai.strategy.AiModelStrategy;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Service
@RequiredArgsConstructor
public class StreamChatServiceImpl implements StreamChatService {

    private final AiModelFactory aiModelFactory;
    private final AiModelConfig aiModelConfig;
    private final ConversationService conversationService;
    private final ConversationMessageService conversationMessageService;
    private final CacheService cacheService;
    private final TokenUsageService tokenUsageService;
    private final ObjectMapper objectMapper;
    private final ExecutorService executor = Executors.newCachedThreadPool();

    private final Map<String, Boolean> streamStopFlags = new ConcurrentHashMap<>();

    @Override
    public SseEmitter streamChat(StreamChatRequest request) {
        log.info("开始流式聊天，请求: {}", request);

        if (!request.isValid()) {
            throw new IllegalArgumentException("聊天请求参数无效: " + request);
        }

        return internalStreamChat(
                request.getMessage(),
                request.getSessionId(),
                request.getConversationId(),
                request.getUserId(),
                request.getModelType(),
                request.getRequestId()
        );
    }

    @Override
    public void setStreamStopFlag(String sessionId) {
        streamStopFlags.put(sessionId, true);
        log.info("设置停止标志，sessionId: {}", sessionId);
    }

    @Override
    public boolean shouldStopStream(String sessionId) {
        Boolean shouldStop = streamStopFlags.get(sessionId);
        return shouldStop != null && shouldStop;
    }

    @Override
    public void clearStreamStopFlag(String sessionId) {
        streamStopFlags.remove(sessionId);
        log.info("清除停止标志，sessionId: {}", sessionId);
    }

    @Override
    public List<String> getStreamingMessages(Long conversationId) {
        return cacheService.getStreamingMessages(conversationId);
    }

    /**
     * 内部流式聊天实现
     */
    private SseEmitter internalStreamChat(String userMessage, String sessionId, Long conversationId,
                                          Long userId, String modelType, String requestId) {
        log.info("开始内部流式聊天，模型: {}, 用户ID: {}, 对话ID: {}, sessionId: {}, requestId: {}",
                modelType, userId, conversationId, sessionId, requestId);

        SseEmitter emitter = new SseEmitter(120_000L);
        StringBuilder fullResponse = new StringBuilder();

        // 清除之前的停止标志
        clearStreamStopFlag(sessionId);

        // 获取模型配置和策略
        AiModelConfig.ModelConfig config = aiModelConfig.getModels().get(modelType);
        AiModelStrategy strategy = aiModelFactory.getStrategy(modelType);

        if (!strategy.validateConfig(config)) {
            emitter.completeWithError(new RuntimeException("模型配置无效: " + modelType));
            return emitter;
        }

        // 使用 final 变量
        final Long finalConversationId = conversationId;
        final String finalUserMessage = userMessage;
        final Long finalUserId = userId;
        final String finalSessionId = sessionId;
        final String finalModelType = modelType;
        final String finalRequestId = requestId;

        // 标记是否已经完成
        final AtomicBoolean isCompleted = new AtomicBoolean(false);

        executor.execute(() -> {
            Long currentConversationId = null;
            String conversationModel = modelType;

            try {
                // 处理对话创建
                currentConversationId = finalConversationId;

                // 如果提供了 conversationId，验证该对话是否存在且属于当前用户
                if (currentConversationId != null) {
                    Conversation existingConversation = conversationService.getConversationById(finalUserId, currentConversationId);
                    if (existingConversation == null) {
                        log.warn("对话不存在或无权访问，对话ID: {}, 用户ID: {}, 将创建新对话",
                                currentConversationId, finalUserId);
                        currentConversationId = null;
                    } else {
                        // 验证模型是否匹配
                        if (!conversationService.validateConversationModel(currentConversationId, finalModelType)) {
                            emitter.completeWithError(new RuntimeException(
                                    "该对话已绑定到 " + existingConversation.getModel() + " 模型，无法使用 " + finalModelType + " 模型"));
                            return;
                        }
                        conversationModel = existingConversation.getModel();
                        log.info("使用现有对话，对话ID: {}, 标题: {}, 模型: {}",
                                currentConversationId, existingConversation.getTitle(), conversationModel);
                    }
                }

                // 如果没有有效的对话ID，创建新对话
                if (currentConversationId == null) {
                    String backendSessionId = generateSessionId();
                    Long newConversationId = createNewConversation(finalUserId, finalUserMessage, backendSessionId, finalModelType);
                    if (newConversationId != null) {
                        currentConversationId = newConversationId;
                        log.info("创建新对话成功，ID: {}, 标题: {}, 模型: {}",
                                currentConversationId, generateConversationTitle(finalUserMessage), finalModelType);
                    } else {
                        throw new RuntimeException("创建对话失败");
                    }
                }

                // 保存用户消息
                ConversationMessage userMsg = saveMessageToDatabase(currentConversationId, "user", finalUserMessage, null);
                if (userMsg == null) {
                    throw new RuntimeException("保存用户消息失败");
                }

                final Integer nextTurn = userMsg.getTurn() + 1;

                // 构建对话上下文
                List<Map<String, String>> conversationContext = buildDatabaseConversationContext(currentConversationId);

                // 创建 final 变量用于内部类
                final Long finalCurrentConversationId = currentConversationId;
                final String finalConversationModel = conversationModel;

                // 创建流式回调 - 支持停止检查
                AiModelStrategy.StreamCallback callback = new AiModelStrategy.StreamCallback() {
                    private int chunkCount = 0;
                    private static final int CHECK_STOP_INTERVAL = 3;

                    @Override
                    public void onContent(String content) {
                        if (isCompleted.get()) {
                            return;
                        }

                        // 定期检查停止标志
                        chunkCount++;
                        if (chunkCount % CHECK_STOP_INTERVAL == 0 && shouldStopStream(finalSessionId)) {
                            log.info("检测到停止标志，停止生成内容，sessionId: {}", finalSessionId);
                            onComplete();
                            return;
                        }

                        try {
                            fullResponse.append(content);

                            // 缓存流式内容
                            cacheService.cacheStreamingMessage(finalCurrentConversationId, content);

                            if (!isCompleted.get()) {
                                // 发送流式消息事件
                                Map<String, Object> messageData = new HashMap<>();
                                messageData.put("type", "message");
                                messageData.put("content", content);
                                messageData.put("conversationId", finalCurrentConversationId);
                                messageData.put("sessionId", finalSessionId);
                                messageData.put("requestId", finalRequestId);

                                emitter.send(SseEmitter.event()
                                        .name("message")
                                        .data(objectMapper.writeValueAsString(messageData)));
                            }
                        } catch (Exception e) {
                            if (!isCompleted.get()) {
                                log.debug("发送流式内容失败，可能连接已关闭: {}", e.getMessage());
                            }
                        }
                    }

                    @Override
                    public void onComplete() {
                        if (isCompleted.getAndSet(true)) {
                            return;
                        }

                        try {
                            boolean wasStopped = shouldStopStream(finalSessionId);

                            // 保存完整的AI回复并获取消息ID
                            Long aiMessageId = null;
                            if (!fullResponse.toString().isEmpty()) {
                                ConversationMessage aiMessage = saveMessageToDatabase(finalCurrentConversationId, "assistant",
                                        fullResponse.toString(), nextTurn);
                                aiMessageId = aiMessage != null ? aiMessage.getId() : null;

                                conversationService.updateConversationTime(finalCurrentConversationId);

                                // 记录token使用
                                int inputTokens = estimateTokens(finalUserMessage) + estimateContextTokens(conversationContext);
                                int outputTokens = estimateTokens(fullResponse.toString());
                                tokenUsageService.recordTokenUsage(finalUserId, finalCurrentConversationId, aiMessageId, finalConversationModel, inputTokens, outputTokens);
                            }

                            // 清除流式缓存
                            cacheService.clearStreamingMessages(finalCurrentConversationId);

                            if (!wasStopped) {
                                Map<String, Object> completionData = new HashMap<>();
                                completionData.put("type", "complete");
                                completionData.put("sessionId", finalSessionId);
                                completionData.put("conversationId", finalCurrentConversationId);
                                completionData.put("requestId", finalRequestId);
                                completionData.put("stopped", wasStopped);
                                completionData.put("contentLength", fullResponse.length());
                                completionData.put("totalTokens", estimateTokens(fullResponse.toString()));

                                emitter.send(SseEmitter.event()
                                        .name("complete")
                                        .data(objectMapper.writeValueAsString(completionData)));
                            }

                            emitter.complete();

                            log.info("流式对话完成，sessionId: {}, 是否停止: {}, 内容长度: {}, 对话ID: {}, 模型: {}",
                                    finalSessionId, wasStopped, fullResponse.length(), finalCurrentConversationId, finalConversationModel);
                        } catch (Exception e) {
                            log.warn("发送完成事件失败，可能连接已关闭: {}", e.getMessage());
                            try {
                                emitter.complete();
                            } catch (Exception ex) {
                                log.debug("完成emitter时发生异常: {}", ex.getMessage());
                            }
                        } finally {
                            clearStreamStopFlag(finalSessionId);
                        }
                    }

                    @Override
                    public void onError(String error) {
                        if (isCompleted.getAndSet(true)) {
                            return;
                        }

                        try {
                            // 清除流式缓存
                            cacheService.clearStreamingMessages(finalCurrentConversationId);

                            Map<String, Object> errorData = new HashMap<>();
                            errorData.put("type", "error");
                            errorData.put("error", error);
                            errorData.put("requestId", finalRequestId);
                            errorData.put("conversationId", finalCurrentConversationId);

                            emitter.send(SseEmitter.event()
                                    .name("error")
                                    .data(objectMapper.writeValueAsString(errorData)));
                        } catch (Exception e) {
                            log.debug("发送错误事件失败，可能连接已关闭: {}", e.getMessage());
                        } finally {
                            try {
                                emitter.complete();
                            } catch (Exception ex) {
                                log.debug("完成emitter时发生异常: {}", ex.getMessage());
                            }
                            clearStreamStopFlag(finalSessionId);
                        }
                    }

                    @Override
                    public boolean shouldStop() {
                        return shouldStopStream(finalSessionId) || isCompleted.get();
                    }
                };

                // 调用模型流式接口
                strategy.chatStream(finalUserMessage, conversationContext, config, callback);

            } catch (Exception e) {
                if (isCompleted.getAndSet(true)) {
                    return;
                }

                log.error("流式聊天处理失败", e);
                try {
                    Map<String, Object> errorData = new HashMap<>();
                    errorData.put("type", "error");
                    errorData.put("error", "请求处理失败: " + e.getMessage());
                    errorData.put("requestId", finalRequestId);

                    emitter.send(SseEmitter.event()
                            .name("error")
                            .data(objectMapper.writeValueAsString(errorData)));
                } catch (Exception ex) {
                    log.debug("发送错误事件失败，可能连接已关闭: {}", ex.getMessage());
                } finally {
                    try {
                        emitter.complete();
                    } catch (Exception ex) {
                        log.debug("完成emitter时发生异常: {}", ex.getMessage());
                    }
                    clearStreamStopFlag(finalSessionId);
                }
            }
        });

        // 设置SSE完成和超时回调
        emitter.onCompletion(() -> {
            log.info("SSE连接完成，sessionId: {}", sessionId);
            isCompleted.set(true);
            clearStreamStopFlag(sessionId);
        });

        emitter.onTimeout(() -> {
            log.info("SSE连接超时，sessionId: {}", sessionId);
            isCompleted.set(true);
            clearStreamStopFlag(sessionId);
        });

        return emitter;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 创建新对话 - 使用新的CreateConversationRequest
     */
    private Long createNewConversation(Long userId, String userMessage, String sessionId, String model) {
        try {
            String title = generateConversationTitle(userMessage);

            // 使用新的CreateConversationRequest
            CreateConversationRequest request = CreateConversationRequest.of(title, model, sessionId, userId);
            var conversationResponse = conversationService.createConversation(request);

            if (conversationResponse != null && conversationResponse.getId() != null) {
                log.info("成功创建对话，ID: {}, 标题: {}, 用户ID: {}, 模型: {}",
                        conversationResponse.getId(), title, userId, model);
                return conversationResponse.getId();
            } else {
                log.error("创建对话失败，返回的对话响应为空");
                return null;
            }
        } catch (Exception e) {
            log.error("创建新对话失败", e);
            return null;
        }
    }

    /**
     * 保存消息到数据库
     */
    private ConversationMessage saveMessageToDatabase(Long conversationId, String role, String content, Integer turn) {
        if (conversationId == null) {
            log.error("无法保存消息，conversationId 为 null");
            return null;
        }

        try {
            if (turn == null) {
                Integer lastTurn = conversationMessageService.getLastTurnByConversationId(conversationId);
                turn = lastTurn != null ? lastTurn + 1 : 1;
            }

            ConversationMessage message = new ConversationMessage();
            message.setConversationId(conversationId);
            message.setTurn(turn);
            message.setRole(ConversationMessage.MessageRole.valueOf(role));
            message.setContent(content);
            message.setCreateTime(java.time.LocalDateTime.now());

            ConversationMessage savedMessage = conversationMessageService.saveMessage(message);

            // 清除对话缓存
            cacheService.evictConversationCache(conversationId);

            log.debug("成功保存消息，对话ID: {}, 角色: {}, 内容长度: {}", conversationId, role, content.length());
            return savedMessage;
        } catch (Exception e) {
            log.error("保存消息失败，对话ID: {}, 角色: {}, 错误: {}", conversationId, role, e.getMessage(), e);
            return null;
        }
    }

    private int estimateTokens(String text) {
        if (text == null || text.isEmpty()) return 0;

        int chineseChars = 0;
        int englishChars = 0;

        for (char c : text.toCharArray()) {
            if (Character.toString(c).matches("[\\u4e00-\\u9fa5]")) {
                chineseChars++;
            } else if (Character.isLetterOrDigit(c) || Character.isWhitespace(c)) {
                englishChars++;
            } else {
                englishChars++;
            }
        }

        int estimatedTokens = (int) Math.ceil(chineseChars / 1.5) + (int) Math.ceil(englishChars / 3.0);
        return Math.max(1, estimatedTokens);
    }

    private int estimateContextTokens(List<Map<String, String>> conversationContext) {
        if (conversationContext == null || conversationContext.isEmpty()) {
            return 0;
        }

        int totalTokens = 0;
        for (Map<String, String> message : conversationContext) {
            String role = message.get("role");
            String content = message.get("content");

            if (role != null) {
                totalTokens += estimateTokens(role);
            }
            if (content != null) {
                totalTokens += estimateTokens(content);
            }
        }

        return totalTokens;
    }

    private String generateSessionId() {
        return "sess_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
    }

    private String generateConversationTitle(String userMessage) {
        if (userMessage == null || userMessage.trim().isEmpty()) {
            return "新对话";
        }
        String title = userMessage.trim();
        return title.length() > 20 ? title.substring(0, 20) + "..." : title;
    }

    private List<Map<String, String>> buildDatabaseConversationContext(Long conversationId) {
        if (conversationId == null) return new ArrayList<>();

        try {
            List<ConversationMessage> messages = conversationMessageService.getMessagesByConversationId(conversationId);
            List<Map<String, String>> context = new ArrayList<>();

            for (ConversationMessage message : messages) {
                Map<String, String> msgMap = new HashMap<>();
                msgMap.put("role", message.getRole().name());
                msgMap.put("content", message.getContent());
                context.add(msgMap);
            }

            return context;
        } catch (Exception e) {
            log.error("构建对话上下文失败", e);
            return new ArrayList<>();
        }
    }
}